home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 2.0 / Internet Publisher's Toolbox.iso / html / rtf2html / wrtf2htm / htmlout.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-21  |  31.9 KB  |  1,315 lines

  1. #include    <stdio.h>
  2. #include    "rtf.h"
  3. #include    "rtftohtml.h"
  4. #include    "string.h"
  5. static void     AppendText();
  6.  
  7.  
  8. static void    PutHex ();
  9. static char    *MapChar();
  10.  
  11. #define MAXNEST 8
  12.  
  13. /* Destinations can be files or strings.  */
  14.  
  15.  
  16. struct SDest
  17.  
  18. HName = {
  19.     NULL, 0, 0
  20. },
  21. HHref = {
  22.     NULL, 0, 0
  23. },
  24. Title = {
  25.     NULL, 0, 0
  26. },
  27. SkipCol = {
  28.     NULL, 0, 0
  29. },
  30. BkName = {
  31.     NULL, 0, 0
  32. },
  33. Item = {
  34.     NULL, 0, 0
  35. };
  36.  
  37. /* SSC codes are used in saving the state */
  38. #define SSCSPECIAL    0
  39. #define SSCSTYLECHG    1
  40. #define SSCNCODES    2    /* Set this to number of SSCodes */
  41.  
  42. struct SSData {
  43.     int Special;
  44.     int cpos;
  45.     InStateStack *TheState;
  46. };
  47.  
  48. struct SSStruct {
  49.     struct SDest SD;
  50.     int alloc;
  51.     int used;
  52.     struct SSData *data;
  53. } PNSave,FNSave;
  54.  
  55. TMatchRec FNMatch;
  56.  
  57. char * (badstyles[256]);    
  58. int anyfoot;
  59. int anyTOC;
  60. int InBody = 0;
  61. int PNText = 0;
  62. int FNText = 0;
  63. int HToCLev = 0;
  64. int oToCLev = 0;
  65. int ToCidx=0;
  66. int ToCText=0;
  67.  
  68. struct FDest {
  69.     char filename[256];        /* Name of output file */
  70.     char wbuff[82];        /* Output buffer */
  71.     FILE *outfd;        /* Output file - (file destinations only) */
  72.     int wrap;            /* should we wrap text or not */
  73.     int HPTags;            /* Highest Paragraph Tag */
  74.     int HTTags;            /* Highest Text Tag */
  75.     int NeedPar;        /* Output Paragraph before next text */
  76.     int InCol2;            /* We are past Column 1 */
  77.     int PTidx;            /* Paragraph Tag Index */
  78.     int TSpecial;        /* Special Tag */
  79.     int cpos;            /* character position */
  80.     int TStack[MAXNEST];    /* Stack of tags */
  81. }
  82.  EmptyFD = {
  83.     "", "",NULL,1, -1, -1, 0, 0, 0,0, 0
  84. },
  85.  File1 = {
  86.     "","", NULL,1, -1, -1, 0, 0, 0,0, 0
  87. },
  88. ToCFile = {
  89.     "","", NULL,1, -1, -1, 0, 0, 0,0, 0
  90. },
  91. Footnote = {
  92.     "","", NULL,1, -1, -1, 0, 0, 0,0, 0
  93. };
  94.  
  95. #define ConvertCaps    ((TStyle&(styleAllCaps|styleSmallCaps))!=0)
  96. int outfuniq = 0;
  97.  
  98. char *LineBuffer = (char *) NULL;
  99.  
  100. FILE *PictFile;
  101. int uniqnum = 0;
  102.  
  103. #define MAXOBUF    8096
  104. int
  105. nextfield(cp, w,  ob,  adj,  EntIsOne)
  106. char *cp;int w; char *ob; int adj; int EntIsOne;
  107. {
  108.     int i,j,br = -1,lp,rp,nb= -1,ow=w;
  109.     for(i=0;i<w&&cp[i]!='\0';i++){
  110.         if(cp[i]==' '||cp[i]=='\t'){
  111.             if(nb==i-1)br=i;
  112.         }    else {
  113.             if(EntIsOne){
  114.                 if(cp[i]=='&'){
  115.                     while(cp[i]!=';'&&cp[i]!='\0'){ 
  116.                         w++;
  117.                         i++;
  118.                     }
  119.                 } else if(cp[i]=='<'){
  120.                     while(cp[i]!='>'&&cp[i]!='\0'){
  121.                         w++;
  122.                         i++;
  123.                     }
  124.                 }
  125.             }
  126.             nb=i;
  127.         }
  128.     }
  129.     if(i==0){
  130.         ob[0]='\0';
  131.         return(0);
  132.     }
  133.     if(cp[i]=='\0'&&nb==i-1)br=i;
  134.     if(br==-1)br=w;
  135.     if(w!=ow){ /* now subtract off any entities not used */
  136.         for(i=br,j=0;i<w&&cp[i]!='\0';i++){
  137.             if(cp[i]=='&'){
  138.                 while(cp[i]!=';'){
  139.                     j++;
  140.                     i++;
  141.                 }
  142.             }
  143.         }
  144.         w-=j;
  145.     }
  146.     switch(adj){
  147.     case AdjL:            /* left justify - no pad */
  148.         lp=0;
  149.         rp=br;
  150.         break;
  151.     case AdjLPad:            /* left justify */
  152.         lp=0;
  153.         rp=w;
  154.         break;
  155.     case AdjRPad:            /* right justify */
  156.         lp=w-br;
  157.         rp=w;
  158.         break;
  159.     case AdjCpad:            /* center */
  160.         lp=(w-br)/2;
  161.         rp=w;
  162.         break;
  163.     }
  164.     if(rp>=MAXOBUF){
  165.         RTFPanic ("Overflowed MAXOBUF too many Entities in a table cell");
  166.     }
  167.     for(i=0;i<lp;i++)ob[i]=' ';
  168.     for(j=0;j<br;i++,j++)ob[i]=cp[j];
  169.     for(;i<rp;i++)ob[i]=' ';
  170.     ob[i]='\0';
  171.     return(br);
  172. }
  173.  
  174. void
  175. putwrap( s,  OD, wrap)
  176. char *s;struct FDest *OD;int wrap;
  177. {
  178.     int i;
  179.     int n;
  180.     char obuff[133];
  181.     /* If writing to a table, just save up the text */
  182.     if(!wrap){
  183.         if(OD->cpos>0){
  184.             OD->wbuff[OD->cpos]='\0';
  185.             fputs(OD->wbuff,OD->outfd);
  186.             fputc('\n',OD->outfd);
  187.         }
  188.         fputs(s,OD->outfd);
  189.         OD->cpos= -1;
  190.         return;
  191.     }
  192.     i=OD->cpos;
  193.     while( *s != '\0'){
  194.         if(i==81){
  195.             n=nextfield(OD->wbuff, 80,  obuff, AdjL,0);
  196.             fputs(obuff,OD->outfd);
  197.             if(n<80){    /* only if we have a break */
  198.                 fputc('\n',OD->outfd);
  199.                 for(;n<81;n++)
  200.                     if(OD->wbuff[n]!=' '&&OD->wbuff[n]!='\t')
  201.                         break;
  202.                 for(i=0;n<81;i++,n++)
  203.                     OD->wbuff[i]=OD->wbuff[n];
  204.             } else  { /* force break at next opportunity */
  205.                 i= -1;
  206.             }
  207.         }
  208.         if(i<0){
  209.             if(strchr(" \t\n",*s)!=NULL){ /*found break */
  210.                 fputc('\n',OD->outfd);
  211.                 i=0;
  212.                 s++;
  213.             } else{
  214.                 fputc(*(s++),OD->outfd);
  215.             }
  216.         } else if(*s=='\n'){
  217.             OD->wbuff[i]='\0';
  218.             fputs(OD->wbuff,OD->outfd);
  219.             fputc(*(s++),OD->outfd);
  220.             i=0;
  221.             continue;
  222.         } else
  223.             OD->wbuff[i++] = *(s++);
  224.     }
  225.     OD->cpos=i;
  226. }
  227.  
  228. HTMLInit()
  229. {
  230.     int i;
  231.  
  232.     if (LineBuffer == (char *) NULL
  233.             && (LineBuffer = RTFAlloc (512)) == (char *) NULL)
  234.         RTFPanic ("cannot allocate line buffer.");
  235.     for(i=0;i<256;i++)
  236.         badstyles[i]=NULL;
  237.     HName.used=0;
  238.     HHref.used=0;
  239.     Title.used=0;
  240.     Item.used=0;
  241.     SkipCol.used=0;
  242.     File1=EmptyFD;
  243.     Footnote=EmptyFD;
  244.     ToCFile=EmptyFD;
  245.     outfuniq=0;
  246.     uniqnum=0;
  247.     ToCidx=1;
  248.     ToCText=0;
  249.     anyfoot=0;
  250.     anyTOC=0;
  251.     InBody = 0;
  252.     HToCLev=0;
  253.     oToCLev = 0;
  254.     for(i=0;i<PNSave.used;i++){
  255.         if(PNSave.data[i].TheState){
  256.                 RTFFree(PNSave.data[i].TheState);
  257.         }
  258.     }
  259.     PNSave.SD.used=0;
  260.     PNSave.used=0;
  261.     for(i=0;i<FNSave.used;i++){
  262.         if(FNSave.data[i].TheState){
  263.                 RTFFree(FNSave.data[i].TheState);
  264.         }
  265.     }
  266.     FNSave.SD.used=0;
  267.     FNSave.used=0;
  268.     FNMatch.Font= "NotAFont";
  269.  
  270.     
  271.     strcpy(File1.filename, OutfileName);
  272.     if (OutfileName[0] != '\0') {
  273.     File1.outfd = OpenOutputFile(OutfileName, "w",FTTEXT);
  274.     if (File1.outfd == NULL) {
  275.         RTFPanic ("Open of %s Failed", OutfileName);
  276.     }
  277.     } else {
  278.     File1.outfd = stdout;
  279.     }
  280.     /* open a file for footnotes */
  281.     sprintf(Footnote.filename, "%s_fn.html", FPrefix);
  282.     Footnote.outfd = OpenOutputFile(Footnote.filename, "w",FTTEXT);
  283.     if (Footnote.outfd == NULL) {
  284.         RTFPanic ("Open of %s Failed", Footnote.filename);
  285.     }
  286.     if(ToC){
  287.         /* open a file for Table of Contents */
  288.         sprintf(ToCFile.filename, "%s_ToC.html", FPrefix);
  289.         ToCFile.outfd = OpenOutputFile(ToCFile.filename, "w",FTTEXT);
  290.         if (ToCFile.outfd == NULL) {
  291.             RTFPanic ("Open of %s Failed", ToCFile.filename);
  292.         }
  293.         putwrap("<html><head>", &ToCFile,ToCFile.wrap);
  294.         putwrap("<!-- This document was created from RTF source by rtftohtml version ", &ToCFile,ToCFile.wrap);
  295.         putwrap(PVers, &ToCFile,ToCFile.wrap);
  296.         putwrap(" -->", &ToCFile,ToCFile.wrap);
  297.         putwrap("</head><body>", &ToCFile,ToCFile.wrap);
  298.     }
  299.     putwrap("<html><head>", &File1,File1.wrap);
  300.     putwrap("<!-- This document was created from RTF source by rtftohtml version ", &File1,File1.wrap);
  301.     putwrap(PVers, &File1,File1.wrap);
  302.     putwrap(" -->", &File1,File1.wrap);
  303.     putwrap("<html><head>", &Footnote,Footnote.wrap);
  304.     putwrap("<!-- This document was created from RTF source by rtftohtml version ", &Footnote,Footnote.wrap);
  305.     putwrap(PVers, &Footnote,Footnote.wrap);
  306.     putwrap(" -->", &Footnote,Footnote.wrap);
  307.     putwrap("</head><body>", &Footnote,Footnote.wrap);
  308. }
  309. static void
  310. TestStyle();
  311.  
  312. HTMLCleanup()
  313. {
  314.     char buff[256];
  315.         
  316.     /* Fake some plain text so that test-style will undo all current markup. */
  317.     TFont="--Not a Font--";
  318.     TStyle=0;
  319.     TSize=9999;
  320.     ParStyle=PMatchArr[0].PStyle;
  321.     TestStyle(&File1);
  322.     if(anyfoot){    /* We have a footnote */
  323.         putwrap("</body></html>", &Footnote,0);
  324.         fclose(Footnote.outfd);
  325.     } else {
  326.         fclose(Footnote.outfd);
  327.         remove (Footnote.filename); 
  328.     }
  329.     if(ToC){
  330.         if(anyTOC){    /* We have a Table of Contents */
  331.             while(oToCLev>0){
  332.                 putwrap("</ol>",&ToCFile,0);
  333.                 oToCLev--;
  334.             }
  335.         putwrap("</body></html>", &ToCFile,0);
  336.             fclose(ToCFile.outfd);
  337.         } else {
  338.             fclose(ToCFile.outfd);
  339.             remove (ToCFile.filename); 
  340.         }
  341.     }
  342.     putwrap("</body></html>", &File1,0);
  343.     if (File1.outfd != stdout)
  344.     fclose(File1.outfd);
  345. }
  346.  
  347. HTMLStartDivert(){
  348.     struct FDest *OD;
  349.     OD = &File1;
  350.     switch (destination) {
  351.     case rtfObjResult:
  352.         if(linkself&&Item.used>0&&!inTable){
  353.             sprintf(LineBuffer,"<a href=\"#%s\">",Item.ptr);
  354.             putwrap(LineBuffer,OD,0);
  355.             Item.used=0;
  356.         }
  357.         break;
  358.     }
  359. }
  360.  
  361. int BkNum=0;
  362. HTMLEndDivert()
  363. {
  364.     struct FDest *OD;
  365.     OD = &File1;
  366.     if (ISS->destination != destination) {
  367.         switch (destination) {
  368.         case rtfPict:
  369.             if(PictFile)fclose(PictFile);
  370.             RTFSetClassCallback(rtfText, PutHTML);
  371.             break;
  372.         case rtfFootnote:
  373.             Footnote.NeedPar = 1;
  374.             Footnote.InCol2 = 0;
  375.             break;
  376.         case rtfObjResult:
  377.             if(linkself){putwrap("</a>",OD,OD->wrap);}
  378.             break;
  379.         case rtfBookmarkStart:
  380.             if(BkName.used>0){
  381.                 sprintf(LineBuffer,"<a name=\"%s\">",BkName.ptr);
  382.                 putwrap(LineBuffer,OD,0);
  383.                 BkName.used=0;
  384.             }else {
  385.                 sprintf(LineBuffer,"<a name=\"RTFtohtmlxx%d\">",BkNum++);
  386.                 putwrap(LineBuffer,OD,OD->wrap);
  387.             }
  388.             break;
  389.         case rtfBookmarkEnd:
  390.             putwrap("</a>",OD,OD->wrap);
  391.             break;
  392.         }
  393.     }
  394.     if(ISS->ToCLev != ToCLev&&ToC&&ToCLev>0){
  395.             putwrap("</a>",&ToCFile,0);
  396.             putwrap("</a>",OD,0);
  397.             ToCText=0;
  398.     }
  399.  
  400. }
  401. int xval=0;
  402. int charnum = 0;
  403. extern int csTop;
  404. void
  405. ReadPict(){
  406.     int mval;
  407.     int level=0;
  408.     int savecsTop;
  409.     if(csTop>0)savecsTop=csTop-1;
  410.     else savecsTop=0;
  411.  
  412.     while (1)
  413.     {
  414.         if (rtfClass == rtfEOF)
  415.             break;
  416.         if (rtfClass == rtfGroup)
  417.         {
  418.             if (rtfMajor == rtfBeginGroup)
  419.                 ++level;
  420.             else if (rtfMajor == rtfEndGroup)
  421.             {
  422.                 if (--level < 1)
  423.                     break;    /* end of initial group */
  424.             }
  425.         } else {
  426.             if(rtfMajor != '\n' && rtfMajor != '\r'
  427.                             && rtfMajor != '\0'){
  428.                 if(rtfMajor <= '9'){
  429.                     mval=rtfMajor-'0';
  430.                 } else if(rtfMajor <= 'F'){
  431.                     mval=rtfMajor-'A'+10;
  432.                 } else {
  433.                     mval=rtfMajor-'a'+10;
  434.                 } 
  435.                 if (++charnum == 2) {
  436.                     xval=xval*16+mval;
  437.                     fputc((char) xval, PictFile);
  438.                     charnum = 0;
  439.                 } else {
  440.                     xval=mval;
  441.                 }
  442.             }
  443.         }
  444.         _RTFGetToken2();
  445.     }
  446.     csTop=savecsTop;
  447. }
  448.  
  449.  
  450. /*
  451.  * This function "cheats" by using rtfMajor (raw input character) rather
  452.  * than rtfMinor (corresponding standard character code).  This is based on
  453.  * the assumption than the function won't see anything other than
  454.  * '0'..'9' and that the result of mapping the standard codes for such chars
  455.  * would be the same chars.
  456.  */
  457.  
  458. static void
  459. PutHex()
  460. {
  461.     int mval;
  462.     if(rtfMajor <= '9'){
  463.         mval=rtfMajor-'0';
  464.     } else if(rtfMajor <= 'F'){
  465.         mval=rtfMajor-'A'+10;
  466.     } else {
  467.         mval=rtfMajor-'a'+10;
  468.     } 
  469.     if (++charnum == 2) {
  470.         xval=xval*16+mval;
  471.         fputc((char) xval, PictFile);
  472.         charnum = 0;
  473.     } else {
  474.         xval=mval;
  475.     }
  476. }
  477.  
  478. char zeros[512];
  479.  
  480. /*
  481.     A placeable Windows metafile is a standard Windows metafile that has an 
  482.     additional 22-byte header. The header contains information about the aspect 
  483.     ratio and original size of the metafile, permitting applications to display 
  484.     the metafile in its intended form. The header for a placeable Windows metafile 
  485.     has the following form: 
  486. typedef struct {
  487.     DWORD   key;
  488.     HANDLE  hmf;
  489.     RECT    bbox;
  490.     WORD    inch;
  491.     DWORD   reserved;
  492.     WORD    checksum;
  493. } METAFILEHEADER;
  494. NOTE: DWORD=4bytes, HANDLE=2,WORD=2,RECT=8.
  495. (Apparently the IBM does byte swapping?)
  496. Following are the members of a placeable metafile header: 
  497. key            Specifies the binary key that uniquely identifies this file type. 
  498.             This member must be set to 0x9AC6CDD7L. 
  499. hmf            Unused; must be zero. 
  500. bbox        Specifies the coordinates of the smallest rectangle that encloses 
  501.             the picture. The coordinates are in metafile units as defined by the inch 
  502.             member. *** the first two points are fixed, the second two are
  503.             the height and width ***
  504. inch        Specifies the number of metafile units to the inch. To avoid numeric 
  505.             overflow, this value should be less than 1440. 
  506.             Most applications use 576 or 1000.  *** we use 1440 ***
  507. reserved    Unused; must be zero. 
  508. checksum    Specifies the checksum. It is the sum (using the XOR operator) of the 
  509.             first 10 words of the header. 
  510.  
  511. */
  512. unsigned char wmfhead[22]={
  513. /* key = */ 0xd7,0xcd,0xc6,0x9a,
  514. /* hmf = */ 0,0,
  515. /* bbox = */ 0xfc,0xff,0xfc,0xff, /*width*/0,0,/*height*/0,0,
  516. /* inch = */ 0xa0,0x05,
  517. /* reserved = */ 0,0,0,0,
  518. /* checksum = */ 0,0};
  519.  
  520. void
  521. NabPicture()
  522. {
  523.     struct FDest *OD;
  524.     /*
  525.      * First create the reference to the picture, and then change the class
  526.      * callback so that the contents of the picture are written to a file. If
  527.      * we are already gathering a link, or the -i option was specified,
  528.      * change the format of the link to IMG.
  529.      */
  530.     char filename[256];
  531.     char rfilename[256];
  532.     char reftext[512];
  533. #ifdef NOTDEF
  534.     if(inTable){
  535.         RTFMsg ("Error, Graphics not allowed in tables - skipping\n");
  536.         context();
  537.         RTFSkipGroup ();
  538.         PopIState();
  539.         return;
  540.     }
  541. #endif
  542.     sprintf(filename, "%s%d.%s", FPrefix, ++outfuniq, PictExt);
  543.     sprintf(rfilename, "%s%d.%s", FPrefixR, outfuniq, PFileExt);
  544.  
  545.     /* find the previous destination */
  546.     if (ISS == NULL) {
  547.         RTFMsg ("Error, State Stack is null\n");
  548.         context();
  549.         RTFPanic ("Error in RTF Input. Please check for valid RTF Input");
  550.     }
  551.     switch (ISS->destination) {
  552.     /* string destinations */
  553.     case rtfFootnote:
  554.     OD = &Footnote;
  555.     break;
  556.     default:
  557.     OD = &File1;
  558.     break;
  559.     }
  560.     if(PNText){    /* We have saved ParNumText */
  561.         PNText=0;
  562.         PlayST(&PNSave);
  563.     }
  564.     if(FNText==1){
  565.             FNText=2;
  566.             PlayST(&FNSave);
  567.             FNText=0;
  568.     }
  569.     if(inTable){
  570.         sprintf(LineBuffer,"<IMG SRC=\"%s\">", rfilename);
  571.         AppendText(&(cell[cellno].cbuff), LineBuffer);
  572.     }else {
  573.         if (IStyle_Chg)    TestStyle(OD);
  574.         if (OD->TSpecial == MTDiscard){
  575.             RTFSkipGroup ();
  576.             PopIState();
  577.             return;
  578.         }
  579.         if (IMG || OD->TSpecial == MTHot) {
  580.             sprintf(LineBuffer,"<IMG SRC=\"%s\">", rfilename);
  581.         } else {
  582.             sprintf(LineBuffer,"<A href=\"%s\">Click here for Picture </A>", rfilename);
  583.         }
  584.         if (OD->NeedPar) {
  585.             DoPmark(OD);
  586.             OD->NeedPar = 0;
  587.         }
  588.         putwrap(LineBuffer,OD,0);
  589.     }
  590.     if(WriteGraf){
  591.     
  592.         PictFile = OpenOutputFile(filename, "wb",PictType);
  593.         if (PictFile == NULL) {
  594.             RTFPanic ("Open of %s Failed", filename);
  595.         }
  596.         if (PictType == FTPICT) {
  597.         fwrite(zeros, 512, 1, PictFile);
  598.            } else if (PictType == FTWMF ) {
  599.                int i;
  600.                /* write a WMF header for a placeable Windows Metafile. */
  601.                /* Calculate Width and Heigth of bounding box */
  602.                wmfhead[10]=(PicGoalWid-4)%256;
  603.                wmfhead[11]=(PicGoalWid-4)/256;
  604.                wmfhead[12]=(PicGoalHt-4)%256;
  605.                wmfhead[13]=(PicGoalHt-4)/256;
  606.                /* compute Checksum */
  607.                wmfhead[20]=0;
  608.                wmfhead[21]=0;
  609.                for(i=0;i<20;i+=2){
  610.                    wmfhead[20]^=wmfhead[i];
  611.                    wmfhead[21]^=wmfhead[i+1];
  612.                    }
  613.                fwrite(wmfhead,22,1,PictFile);
  614.            }
  615.            ReadPict();
  616.            RTFSetClassCallback (rtfText, PutHTML);
  617.            PopIState();
  618.     } else {
  619.         RTFSkipGroup ();
  620.         PictFile=NULL;
  621.         PopIState();
  622.     }
  623. }
  624.  
  625.  
  626.  
  627.  
  628. static void
  629. TestStyle(OD)
  630.     struct FDest *OD;
  631. {
  632. /*
  633.     Change the style of the output text to the new style.
  634.     If the style changes, force correct nesting of HTML tags.
  635. */
  636.     int PMidx, i, j,k;
  637.     int OldPMidx;
  638.     int OldTSpecial = OD->TSpecial;
  639.     if (!InBody) {
  640.         /*
  641.          * If we get here, we have text destined for the body. close out
  642.          * the head section.
  643.          */
  644.         if (Title.used) {
  645.         sprintf(LineBuffer,"<title>%s</title>", Title.ptr);
  646.         putwrap(LineBuffer, &File1,1);
  647.         }
  648.         putwrap("</head><body>", &File1,1);
  649.         InBody = 1;
  650.     }
  651.     
  652.     if(OD->HPTags<0)
  653.         OldPMidx = -1;
  654.     else
  655.         OldPMidx = OD->TStack[OD->HPTags];
  656.     /* Look for Special Text Style Matches - these override normal processing */
  657.     IStyle_Chg = 0;
  658.     OD->TSpecial = 0;
  659.     
  660.     
  661.     /* Find a match on the new paragraph and text styles */
  662.     PMidx = PMatchLen;        /* to catch a null ParStyle */
  663.     for(k=0;ParStyle[k]!='\0';k+=i){/* for each alias in ParStyle */
  664.         /* find the size of the ParStyle alias */
  665.         for(i=0;ParStyle[k+i]!='\0'&&ParStyle[k+i]!=',';i++);
  666.         for (PMidx = 0; PMidx < PMatchLen; PMidx++) {
  667.             if (strncmp(PMatchArr[PMidx].PStyle, ParStyle,i) == 0) {
  668.                 break;
  669.             }
  670.         }
  671.         if (PMidx != PMatchLen)break;
  672.     }
  673.  
  674.     if (PMidx == PMatchLen){
  675.         PMidx = 0;        /* The first entry is the default */
  676.         if(strcmp(ParStyle,"")!=0){
  677.             for(i=0;i<256&&badstyles[i]!=NULL;i++) /* Save off mismatches */
  678.                 if(strcmp(badstyles[i],ParStyle)==0)
  679.                     break;
  680.             if(i<256&&badstyles[i]==NULL){
  681.                 badstyles[i]=ParStyle;
  682.                 RTFMsg ("Unknown Paragraph style: %s\n",ParStyle);
  683.             }
  684.         }
  685.     }
  686.  
  687.     
  688.     
  689.     
  690.     if(PMatchArr[PMidx].PTidx>MTSPECIAL&&
  691.         (PMatchArr[PMidx].PTidx != MTHref || OD != &Footnote)){
  692.         OD->TSpecial=PMatchArr[PMidx].PTidx;
  693.     } else {
  694.         for (i = 0; i < TMatchLen; i++) {
  695.             if ((TMatchArr[i].TStyle == (TMatchArr[i].TMask & TStyle)) &&
  696.                 (TMatchArr[i].Font[0] == '\0' || strcmp(TMatchArr[i].Font, TFont) == 0) &&
  697.                 (TMatchArr[i].FSize == 0 || TMatchArr[i].FSize == TSize)) {
  698.                 /* can't have hot text in footnote */
  699.                 if (TMatchArr[i].TTidx == MTHref && OD == &Footnote)
  700.                     continue;
  701.                 if (TMatchArr[i].TTidx > MTSPECIAL) {
  702.                     OD->TSpecial = TMatchArr[i].TTidx;
  703.                     break;
  704.                 }
  705.             }
  706.         }
  707.     }
  708.     if (inTable){ /* force specials off */
  709.         OD->TSpecial=0;
  710.         ParStyle="_Table";
  711.     }
  712.     if (FNMatch.TStyle == (TStyle) &&
  713.         strcmp(FNMatch.Font, TFont) == 0 &&
  714.          FNMatch.FSize == TSize) {
  715.             OD->TSpecial = MTFootNote;
  716.     }
  717.     if (OldTSpecial != OD->TSpecial) {
  718.         switch(OldTSpecial){
  719.         case MTName:
  720.             putwrap("\"> </a>", OD,0);
  721.             OD->wrap=PTagArr[OD->PTidx].DoFold;
  722.             break;
  723.         case MTHref:
  724.             putwrap("\">", OD,0);
  725.             if(OD->TSpecial!=MTHot){
  726.                 RTFMsg ("Error, at end of href, hot text not found\n");
  727.                 context();
  728.                 putwrap("</a>", OD,0);
  729.             }
  730.             OD->wrap=PTagArr[OD->PTidx].DoFold;
  731.             break;
  732.         case MTHot:
  733.             putwrap("</a>",OD,OD->wrap);
  734.             break;
  735.         case MTFootNote:
  736.             if (OD == &File1) {
  737.                 putwrap("]</a>", OD,OD->wrap);
  738.                 FNMatch.Font= "NotAFont";
  739.             } else {
  740.                 putwrap("]</a>",OD,OD->wrap);
  741.             }
  742.             break;
  743.         }
  744.     }
  745.     if (OD->TSpecial != 0){
  746.           if (OldTSpecial != OD->TSpecial) {
  747.             while (OD->HTTags > OD->HPTags) {
  748.                 putwrap(TTagArr[TMatchArr[OD->TStack[OD->HTTags]].TTidx].EndTag,
  749.                 OD,OD->wrap);
  750.                 OD->HTTags--;
  751.             }
  752.             switch(OD->TSpecial){
  753.             case MTName:
  754.                 if (OD->NeedPar) {
  755.                     putwrap(PTagArr[OD->PTidx].ParTag, OD,OD->wrap);
  756.                     OD->NeedPar = 0;
  757.                    }
  758.                 putwrap("<a name=\"", OD,0);
  759.                 OD->wrap=0;
  760.                    break;
  761.             case MTHref:
  762.                 if (OD->NeedPar) {
  763.                     putwrap(PTagArr[OD->PTidx].ParTag, OD,OD->wrap);
  764.                     OD->NeedPar = 0;
  765.                    }
  766.                 putwrap("<a href=\"", OD,0);
  767.                 OD->wrap=0;
  768.                    break;
  769.             case MTHot:
  770.                 if(OldTSpecial!=MTHref){
  771.                     RTFMsg ("Error, hot text found without preceding href\n");
  772.                        context();                      
  773.                 }                
  774.                 break;
  775.             case MTFootNote:
  776.                 if (OD->NeedPar) {
  777.                     putwrap(PTagArr[OD->PTidx].ParTag, OD,OD->wrap);
  778.                     OD->NeedPar = 0;
  779.                 }
  780.                 if (OD == &File1) {
  781.                     anyfoot=1;
  782.                     sprintf(LineBuffer,"<a href=\"%s_fn.html#fn%d\">[", FPrefixR,uniqnum);
  783.                     putwrap(LineBuffer,OD,OD->wrap);
  784.                 } else {
  785.                     sprintf(LineBuffer,"<a name=\"fn%d\">[", uniqnum++);
  786.                     putwrap(LineBuffer,OD,OD->wrap);
  787.                 }
  788.                 break;
  789.             }
  790.         }
  791.         return;
  792.     }
  793.  
  794.     OD->PTidx = PMatchArr[PMidx].PTidx;
  795.     if (PMidx != OldPMidx) { /* Paragraph Style changed */
  796.         int pushpop=0;
  797.         /* Pop all of the Text Styles */
  798.         while (OD->HTTags > OD->HPTags) {
  799.             putwrap(TTagArr[TMatchArr[OD->TStack[OD->HTTags]].TTidx].EndTag,
  800.             OD,OD->wrap);
  801.             OD->HTTags--;
  802.         }
  803.         if (PMatchArr[PMidx].NestLev > OD->HPTags + 1) {
  804.             RTFMsg ("Error, found style:%s at a nesting level of %d\n"
  805.             ,ParStyle, OD->HPTags);
  806.             context();
  807.         }
  808.         while (OD->HPTags >= PMatchArr[PMidx].NestLev) {
  809.             /* Pop Paragraph Tags  */
  810.             if(OD->TStack[OD->HPTags] == PMidx){
  811.                 pushpop=1;
  812.                 break;
  813.             } else {
  814.                 if (strcmp(PTagArr[PMatchArr[OD->TStack[OD->HPTags]].PTidx].EndTag, "") != 0
  815.                 && strcmp(PTagArr[OD->PTidx].StartTag, "") == 0) {
  816.                 /* if there was a closing tag, we no longer need a paragraph */
  817.                 OD->NeedPar = 0;
  818.                 }
  819.                 putwrap(PTagArr[PMatchArr[OD->TStack[OD->HPTags]].PTidx].EndTag, OD,
  820.                 PTagArr[PMatchArr[OD->TStack[OD->HPTags]].PTidx].DoFold);
  821.                 OD->HPTags--;
  822.             }
  823.         }
  824.         if(!pushpop){
  825.             if(OD->HPTags >= 0&&!PTagArr[PMatchArr[OD->TStack[OD->HPTags]].PTidx].CanNest) {
  826.                 /* Nesting Error */
  827.                 RTFMsg ("Error, can't use style:%s within %s\n",
  828.                 ParStyle,
  829.                 PMatchArr[OD->TStack[OD->HPTags]].PStyle);
  830.                 context();
  831.             }
  832.             /* Now push the new style */
  833.             OD->HPTags++;
  834.             OD->TStack[OD->HPTags] = PMidx;
  835.             if (strcmp(PTagArr[OD->PTidx].StartTag, "") != 0) {
  836.                 /* if there is a Starting tag, we no longer need a paragraph */
  837.                 putwrap(PTagArr[OD->PTidx].StartTag, OD,PTagArr[OD->PTidx].DoFold);
  838.                 OD->NeedPar = 0;
  839.             }
  840.         }
  841.         OD->HTTags = OD->HPTags;
  842.           OD->wrap=PTagArr[OD->PTidx].DoFold;
  843.     }
  844.     if (OD->NeedPar) {
  845.         DoPmark(OD);
  846.         OD->NeedPar = 0;
  847.     }
  848.       if(ToCLev==0){
  849.              HToCLev=PTagArr[PMatchArr[PMidx].PTidx].ToCLev;
  850.         } else {
  851.              HToCLev=ToCLev;
  852.         }
  853.  
  854.     /* Check remaining Text Styles to see if they should be popped */
  855.     for (i = OD->HPTags + 1; i <= OD->HTTags; i++) {
  856.     if ((TMatchArr[OD->TStack[i]].TStyle != (TMatchArr[OD->TStack[i]].TMask & TStyle)) ||
  857.         (TMatchArr[OD->TStack[i]].Font[0] != '\0' && strcmp(TMatchArr[OD->TStack[i]].Font, TFont) != 0) ||
  858.         (TMatchArr[OD->TStack[i]].FSize != 0 && TMatchArr[OD->TStack[i]].FSize != TSize)) {
  859.         while (OD->HTTags >= i) {
  860.         putwrap(TTagArr[TMatchArr[OD->TStack[OD->HTTags]].TTidx].EndTag,
  861.             OD,OD->wrap);
  862.         OD->HTTags--;
  863.         }
  864.     }
  865.     }
  866.     /* Now check all Text Styles and see if anything else must be pushed */
  867.     if (PTagArr[PMatchArr[OD->TStack[OD->HPTags]].PTidx].AllowText) {
  868.     for (i = 0; i < TMatchLen; i++) {
  869.         if ((TMatchArr[i].TStyle == (TMatchArr[i].TMask & TStyle)) &&
  870.         (TMatchArr[i].Font[0] == '\0' || strcmp(TMatchArr[i].Font, TFont) == 0) &&
  871.         (TMatchArr[i].FSize == 0 || TMatchArr[i].FSize == TSize)) {
  872.         for (j = OD->HPTags + 1; j <= OD->HTTags; j++) {
  873.             if (TMatchArr[OD->TStack[j]].TTidx == TMatchArr[i].TTidx)
  874.             break;
  875.         }
  876.         if (j > OD->HTTags) {
  877.             /* didn't find it - push it on */
  878.             OD->HTTags++;
  879.             OD->TStack[OD->HTTags] = i;
  880.             if (TMatchArr[i].TTidx >= TTagLen) {
  881.                 RTFMsg ("Fatal Error");
  882.                 context();
  883.                 RTFPanic ("Internal trap - tried to push special: %d\n",TMatchArr[i].TTidx);
  884.             }
  885.             putwrap(TTagArr[TMatchArr[i].TTidx].StartTag,
  886.             OD,OD->wrap);
  887.         }
  888.         }
  889.     }
  890.     }            
  891. }
  892.  
  893. DoPmark(OD)
  894.     struct FDest *OD;
  895. {
  896.     /* pop all text styles, print the paragraph mark and push them back */
  897.     int i;
  898.     OD->NeedPar=0;
  899.     for(i=OD->HTTags;i>OD->HPTags;i--){
  900.         putwrap(TTagArr[TMatchArr[OD->TStack[i]].TTidx].EndTag,
  901.         OD,OD->wrap);
  902.     }
  903.     putwrap(PTagArr[OD->PTidx].ParTag, OD,OD->wrap);
  904.     for(i=OD->HPTags+1; i<=OD->HTTags;i++){
  905.         putwrap(TTagArr[TMatchArr[OD->TStack[i]].TTidx].StartTag,
  906.         OD,OD->wrap);
  907.     }
  908. }
  909.  
  910. PutSpecial(Special)
  911.     int Special;
  912. {
  913.     int i,j,n,opos,dataleft;
  914.     char orec[MAXOBUF];
  915.     struct FDest *OD;
  916.     switch (destination) {
  917.     /* string destinations */
  918.     case rtfITitle:
  919.     case rtfInfo:
  920.     case rtfISubject:
  921.     case rtfIAuthor:
  922.     case rtfIOperator:
  923.     case rtfIKeywords:
  924.     case rtfIComment:
  925.     case rtfIVersion:
  926.     case rtfIDoccomm:
  927.     return;
  928.     case rtfParNumText:
  929.         SaveSt(&PNSave,1+Special);
  930.         PNText=1;
  931.         return;
  932.     /* file destinations */
  933.     case rtfHeader:
  934.     case rtfHeaderLeft:
  935.     case rtfHeaderRight:
  936.     case rtfHeaderFirst:
  937.     case rtfFooter:
  938.     case rtfFooterLeft:
  939.     case rtfFooterRight:
  940.     case rtfFooterFirst:
  941.     return;
  942.     case rtfFootnote:
  943.     OD = &Footnote;
  944.     break;
  945.     default:
  946.     OD = &File1;
  947.     break;
  948.     }
  949.     if(PNText){    /* We have saved ParNumText */
  950.         PNText=0;
  951.         PlayST(&PNSave);
  952.     }
  953.     if(FNText==1){
  954.             FNText=2;
  955.             PlayST(&FNSave);
  956.             FNText=0;
  957.     }
  958.     if (IStyle_Chg){
  959.         if(inTable){
  960.             TFont="--Not a Font--";
  961.             TStyle=0;
  962.                TSize=9999;
  963.                ParStyle="_Table";
  964.         }
  965.         TestStyle(OD);
  966.     }
  967.     if (OD->NeedPar) {
  968.         DoPmark(OD);
  969.         OD->NeedPar = 0;
  970.     }
  971.     switch (Special) {
  972.     case rtfRow:    /* Clear out all saved cell data */
  973.         dataleft=1;
  974.         for(i=firstcell;i<lastcell;i++)
  975.             cell[i].cpos=0;
  976.         while(dataleft){
  977.             dataleft=0;
  978.             opos=0;
  979.             for(i=firstcell;i<lastcell;i++){
  980.                 if(cell[i].merge||cell[i].cpos>=cell[i].cbuff.used){
  981.                     for(j=0;j<=cell[i].width;j++){
  982.                         orec[opos++]=' ';
  983.                     }
  984.                     continue;
  985.                     }
  986.                 cell[i].cpos+=nextfield(&(cell[i].cbuff.ptr[cell[i].cpos]), 
  987.                     cell[i].width-1,  &(orec[opos]), cell[i].just,1);
  988.                 /* skip leading blanks */
  989.                 while(cell[i].cbuff.ptr[cell[i].cpos]==' '||cell[i].cbuff.ptr[cell[i].cpos]=='\t')
  990.                     cell[i].cpos++;
  991.                 n=strlen(&(orec[opos]));
  992.                 orec[opos+n]=' ';
  993.                 orec[opos+n+1]=' ';
  994.                 opos+=n+2;         
  995.                 if(cell[i].cpos<cell[i].cbuff.used)
  996.                     dataleft=1;
  997.             }
  998.             orec[opos++]='\n';
  999.             orec[opos]='\0';
  1000.             putwrap(orec, OD,0);
  1001.         }
  1002.         for(i=firstcell;i<lastcell;i++)
  1003.             cell[i].cbuff.used=0;
  1004.         break;
  1005.     case rtfPar:
  1006.         if(inTable){
  1007.             AppendText(&(cell[cellno].cbuff), " ");
  1008.             return;
  1009.         }           
  1010.         if (OD->TSpecial == MTDiscard)
  1011.             return;
  1012.         if (OD->InCol2==0 && PTagArr[OD->PTidx].DeleteCol1==1) { 
  1013.             /* We deleted Everything */
  1014.             if(SkipCol.used>0){
  1015.                 RTFMsg ("Warning - required Tab missing from list entry - recovering text");
  1016.                 context();
  1017.                 putwrap(SkipCol.ptr,OD,OD->wrap);
  1018.             }
  1019.         }
  1020.         OD->NeedPar = 1;
  1021.         OD->InCol2 = 0;
  1022.         SkipCol.used=0;
  1023.         if(ToC&&ToCText&&OD==&File1&&HToCLev>0){
  1024.             putwrap("</a>",&ToCFile,0);
  1025.             putwrap("</a>",OD,0);
  1026.             ToCText=0;
  1027.         }
  1028.         break;
  1029.     case rtfTab:
  1030.         if(inTable){
  1031.             AppendText(&(cell[cellno].cbuff), " ");
  1032.             return;
  1033.         }           
  1034.         if (OD->TSpecial == MTDiscard)
  1035.             return;
  1036.         if (!OD->InCol2) {
  1037.             putwrap(PTagArr[OD->PTidx].Col2Tag, OD,OD->wrap);
  1038.             SkipCol.used=0;
  1039.             OD->InCol2 = 1;
  1040.         } else {
  1041.             putwrap(PTagArr[OD->PTidx].TabTag, OD,OD->wrap);
  1042.         }
  1043.         break;
  1044.     }
  1045. }
  1046.  
  1047.  
  1048.  
  1049. context(){
  1050.     int cptr;
  1051.     char ctxbuff[256];
  1052.     sprintf (ctxbuff,"At line %ld, position %d.\n",rtfLineNum, rtfLinePos);
  1053.  
  1054.     RTFMsg (ctxbuff);
  1055. }
  1056.  
  1057. void
  1058. PutHTMLString(p)
  1059.     char *p;
  1060. {
  1061.     int i, j;
  1062.     struct FDest *OD;
  1063.     switch (destination) {
  1064.     /* string destinations */
  1065.     case rtfITitle:
  1066.     AppendText(&Title, p);
  1067.     return;
  1068.     case rtfInfo:
  1069.     case rtfISubject:
  1070.     case rtfIAuthor:
  1071.     case rtfIOperator:
  1072.     case rtfIKeywords:
  1073.     case rtfIComment:
  1074.     case rtfIVersion:
  1075.     case rtfIDoccomm:
  1076.     return;
  1077.     case rtfParNumText:
  1078.         AppendText(&PNSave.SD, p);
  1079.         if (IStyle_Chg)SaveSt(&PNSave,0);
  1080.         PNText=1;
  1081.         return;
  1082.     case rtfObjItem:
  1083.     AppendText(&Item, p);
  1084.     return;
  1085.     case rtfBookmarkStart:
  1086.     AppendText(&BkName, p);
  1087.     return;
  1088.     case rtfBookmarkEnd:
  1089.     return;
  1090.     /* file destinations */
  1091.     case rtfHeader:
  1092.     case rtfHeaderLeft:
  1093.     case rtfHeaderRight:
  1094.     case rtfHeaderFirst:
  1095.     case rtfFooter:
  1096.     case rtfFooterLeft:
  1097.     case rtfFooterRight:
  1098.     case rtfFooterFirst:
  1099.     return;
  1100.     case rtfFootnote:
  1101.     OD = &Footnote;
  1102.     break;
  1103.     default:
  1104.     OD = &File1;
  1105.     break;
  1106.     }    
  1107.     if(PNText){    /* We have saved ParNumText */
  1108.         PNText=0;
  1109.         PlayST(&PNSave);
  1110.     }
  1111.     if(inTable){
  1112.         AppendText(&(cell[cellno].cbuff), p);
  1113.         return;
  1114.     }
  1115.     if(FNText==1){
  1116.             FNText=2;
  1117.             PlayST(&FNSave);
  1118.             FNText=0;
  1119.     } else if(FNText==0&&IStyle_Chg&&destination!=rtfFootnote) { /* We have a candidate footnote */
  1120.         FNText=1;
  1121.         AppendText(&FNSave.SD, p);
  1122.         SaveSt(&FNSave,0);
  1123.         return;
  1124.     }
  1125.     if (IStyle_Chg){
  1126.         TestStyle(OD);
  1127.     }
  1128.     if (OD->TSpecial == MTDiscard)
  1129.     return;
  1130.     if (OD->InCol2==0 && PTagArr[OD->PTidx].DeleteCol1==1){
  1131.         AppendText(&SkipCol, p);
  1132.         return;
  1133.     }
  1134.     if (OD->NeedPar) {
  1135.         DoPmark(OD);
  1136.         OD->NeedPar = 0;
  1137.     }
  1138.     /* If we are looking at <,> or & that have been translated
  1139.         and we are in MHLiteral, untranslated them.
  1140.     */
  1141.     if (OD->TSpecial == MTLiteral){
  1142.         if(strcmp(p,"<")==0)p="<";
  1143.         else if(strcmp(p,">")==0)p=">";
  1144.         else if(strcmp(p,"&")==0)p="&";
  1145.     } else if ((ConvertCaps) && p[0] != '&' && p[0] != '[') {
  1146.     /* do uppercasing if string doesn't begin with '&' or '[' */
  1147.     char *s = p;
  1148.  
  1149.     while (*s != '\0') {
  1150.         if (islower(*s))
  1151.         *s = toupper(*s);
  1152.         ++s;
  1153.     }
  1154.     }
  1155.     if(ToC&&OD==&File1&&HToCLev>0){
  1156.         while(oToCLev>HToCLev){
  1157.             putwrap("</ol>",&ToCFile,0);
  1158.             oToCLev--;
  1159.         }
  1160.         while(oToCLev<HToCLev){
  1161.             putwrap("<ol>",&ToCFile,0);
  1162.             oToCLev++;
  1163.         }
  1164.         if(ToCText==0){
  1165.             anyTOC=1;
  1166.             sprintf(LineBuffer,"\n<li><a href=\"%s.html#RTFToC%d\">", FPrefixR,ToCidx);
  1167.             putwrap(LineBuffer,&ToCFile,0);
  1168.             sprintf(LineBuffer,"<a name=\"RTFToC%d\">",ToCidx++);
  1169.             putwrap(LineBuffer,OD,0);
  1170.             ToCText=1;
  1171.         }
  1172.         putwrap(p,&ToCFile,0);
  1173.     }
  1174.  
  1175.     putwrap(p, OD,OD->wrap);
  1176. }
  1177.  
  1178. void
  1179. PutHTML()
  1180. {
  1181.     char *p;
  1182.     p = MapChar(rtfMinor);
  1183.     PutHTMLString(p);
  1184. }
  1185.  
  1186.  
  1187.  
  1188. /*
  1189.  * Map a standard character code to an output string.
  1190.  * Returns pointer to static string.
  1191.  */
  1192.  
  1193. static char *
  1194. MapChar(stdCode)
  1195.     int stdCode;
  1196. {
  1197.     static char buf[100];
  1198.     char *oStr;
  1199.  
  1200.     if (stdCode == rtfSC_nothing){
  1201.     sprintf(buf,"&#%d;",rtfMajor);
  1202.     RTFMsg("Invalid Character Code \\`%x - outputting &#%d;\n",rtfMajor,rtfMajor);
  1203.     }else {
  1204.     oStr = outMap[stdCode];
  1205.     if (oStr == (char *) NULL) {    /* no output sequence in map */
  1206.         sprintf(buf, "[[%s]]", RTFStdCharName(stdCode));
  1207.         RTFMsg("No output translation for :%s\n",RTFStdCharName(stdCode));
  1208.     } else
  1209.         (void) strcpy(buf, oStr);
  1210.     }
  1211.     return (buf);
  1212. }
  1213.  
  1214.  
  1215. static void
  1216. AppendText(OD, text)
  1217.     struct SDest *OD;
  1218.     char *text;
  1219. {
  1220.     int need;
  1221.     char *ptr;
  1222.  
  1223.     need = OD->used + 1 + strlen(text);    /* need space for next char + '\0' */
  1224.     if (OD->alloc < need) {
  1225.     OD->alloc += DSALLOC * (1 + (need / DSALLOC));
  1226.     ptr = (char *) RTFAlloc(
  1227.         (int) sizeof(char) * OD->alloc);
  1228.     if (ptr == NULL) {
  1229.         RTFMsg ("Memory Allocation Failed\n");
  1230.         context();
  1231.        RTFPanic ("");
  1232.     }
  1233.     if (OD->ptr != NULL) {
  1234.         (void) strcpy(ptr, OD->ptr);
  1235.         RTFFree(OD->ptr);
  1236.     }
  1237.     OD->ptr = ptr;
  1238.     }
  1239.     strcpy(&(OD->ptr[(OD->used)]), text);
  1240.     OD->used += strlen(text);
  1241. }
  1242.  
  1243. /* 
  1244.     Need to save off  Special Character (int)
  1245.     and current text position
  1246.     and current save state pointer
  1247. */
  1248. SaveSt(SS,Special)
  1249. struct SSStruct *SS;
  1250. {
  1251.     struct SSData *ptr;
  1252.     int i;
  1253.     if(SS->alloc==SS->used){
  1254.         SS->alloc+=40;
  1255.         ptr = (struct SSData *) RTFAlloc(
  1256.         (int) sizeof(struct SSData) * SS->alloc);
  1257.         if (ptr == NULL) {
  1258.             RTFMsg ("Memory Allocation Failed\n");
  1259.             context();
  1260.            RTFPanic ("");
  1261.         }
  1262.         if(SS->data != NULL) {
  1263.             for(i=0;i<SS->used;i++){
  1264.                 ptr[i]=SS->data[i];
  1265.             }
  1266.             RTFFree(SS->data);
  1267.         }
  1268.         SS->data=ptr;
  1269.     }
  1270.     SS->data[SS->used].Special=Special;
  1271.     if(IStyle_Chg){
  1272.         SS->data[SS->used].TheState=SaveIState();
  1273.     } else {
  1274.         SS->data[SS->used].TheState=NULL;
  1275.     }
  1276.     SS->data[SS->used++].cpos=SS->SD.used;
  1277. }
  1278. PlayST(SS)
  1279. struct SSStruct *SS;
  1280. {
  1281.     int i,tidx=0;
  1282.     InStateStack *SavedState;
  1283.     char savchar;
  1284.     SavedState=SaveIState();
  1285.     for(i=0;i<SS->used;i++){
  1286.         if(SS->data[i].TheState){
  1287.             RestoreIState(SS->data[i].TheState);
  1288.             SS->data[i].TheState=NULL;
  1289.             if(destination==rtfParNumText){
  1290.                 destination=SavedState->destination;
  1291.                 ParStyle=SavedState->ParStyle;
  1292.             } else if(destination!=rtfFootnote &&
  1293.                 SavedState->destination==rtfFootnote){
  1294.                 FNMatch.TStyle = TStyle;
  1295.                 FNMatch.Font= TFont;
  1296.                 FNMatch.FSize = TSize;
  1297.             }
  1298.         }
  1299.         /* First dispense with all leading text */
  1300.         if(tidx < SS->SD.used){
  1301.             savchar=SS->SD.ptr[SS->data[i].cpos];
  1302.             SS->SD.ptr[SS->data[i].cpos]='\0';
  1303.             PutHTMLString(&(SS->SD.ptr[tidx]));
  1304.             tidx=SS->data[i].cpos;
  1305.             SS->SD.ptr[SS->data[i].cpos]=savchar;
  1306.         }
  1307.         if(SS->data[i].Special){
  1308.             PutSpecial(SS->data[i].Special-1);
  1309.         }
  1310.     }
  1311.     SS->SD.used=0;
  1312.     SS->used=0;
  1313.     RestoreIState(SavedState);
  1314. }
  1315.